using System;
using System.Text;
using Microsoft.Practices.ComponentModel;
using EnvDTE;
using System.Diagnostics;
using System.IO;
using Microsoft.Practices.RecipeFramework.Configuration;
using Microsoft.Practices.RecipeFramework;
using Microsoft.Practices.RecipeFramework.Library;
using System.Windows.Forms.Design;
using System.Windows.Forms;
using Microsoft.Practices.RecipeFramework.Extensions.CommonHelpers;
using System.Globalization;
using Resources=Microsoft.Practices.RepositoryFactory.Properties.Resources;

namespace Microsoft.Practices.RepositoryFactory.Actions.VisualStudio
{
    [ServiceDependency(typeof(DTE))]
    [ServiceDependency(typeof(IUIService))]
    public class AddItemFromStringToProjectItemAction : ConfigurableAction
    {
        #region Input Properties

        private string content;
        /// <summary>
        /// The string with the content of the item. In most cases it is a class
        /// generated using the T3 engine.
        /// </summary>
        [Input(Required=true)]
        public string Content
        {
            get { return content; }
            set { content = value; }
        }

        private string targetFileName;
        /// <summary>
        /// Name of the file where the item is to be stored.
        /// </summary>
        [Input(Required=true)]
        public string TargetFileName
        {
            get { return targetFileName; }
            set { targetFileName = value; }
        }

        private ProjectItem inputProjectItem;
        /// <summary>
        /// Project item where the item it to be inserted.
        /// </summary>
        [Input(Required = true)]
        public ProjectItem InputProjectItem
        {
            get { return inputProjectItem; }
            set { inputProjectItem = value; }
        }

        private bool open = true;
        /// <summary>
        /// A flag to indicate if the newly created item should be shown
        /// in a window.
        /// </summary>
        [Input]
        public bool Open
        {
            get { return open; }
            set { open = value; }
        }

        private bool overwrite = true;

        [Input]
        public bool Overwrite
        {
            get { return overwrite; }
            set { overwrite = value; }
        }

        private bool showConfirmation = true;

        [Input]
        public bool ShowConfirmation
        {
            get { return showConfirmation; }
            set { showConfirmation = value; }
        }
        #endregion Input Properties

        #region Output Properties

        private EnvDTE.ProjectItem projectItem;
        /// <summary>
        /// A property that can be used to pass the creted item to
        /// a following action.
        /// </summary>
        [Output]
        public EnvDTE.ProjectItem ProjectItem
        {
            get { return projectItem; }
            set { projectItem = value; }
        }

        #endregion Output Properties
        /// <summary>
        /// The method that creates a new item from the intput string.
        /// </summary>
        public override void Execute()
        {
            DTE vs = GetService<DTE>(true);
            string tempfile = Path.GetTempFileName();
            using (StreamWriter sw = new StreamWriter(tempfile, false, Encoding.UTF8))
            {
                sw.WriteLine(content);
            }

            projectItem = DteHelperEx.FindItemByName(inputProjectItem.ProjectItems, targetFileName, false);

            string fileFullPath = 
                Path.Combine(
                    Path.Combine(
                        Path.GetDirectoryName(inputProjectItem.ContainingProject.FileName),
                            inputProjectItem.Name),
                    targetFileName);

            if(projectItem != null)
            {
                // the file is already in the project
                if(overwrite)
                {
                    // the item already exists in the project, overwrite it
                    // this is a work around for visual studio: if the file exists and there's an
                    // editor over it, the call to AddFromTemplate will succeed but the contents
                    // of the file will be the ones in the editor, not the ones in the template

                    if(showConfirmation)
                    {
                        IUIService uiService = GetService<IUIService>();

                        if(uiService.ShowMessage(
                            string.Format(CultureInfo.CurrentCulture, Resources.ConfirmOverwrite, targetFileName), 
                            null, 
                            MessageBoxButtons.YesNo) == DialogResult.Yes)
                        {
                            File.Copy(tempfile, fileFullPath, true);
                        }
                    }
                    else
                    {
                        File.Copy(tempfile, fileFullPath, true);
                    }
                }
            }
            else
            {
                // the item doesn't exist in the project (but might be in the file system)
                if(File.Exists(fileFullPath))
                {
                    // the file exists, but it's not in the project, remove the file
                    File.Delete(fileFullPath);
                }

                // add the item to the project, creating the physical file for it
                projectItem = inputProjectItem.ProjectItems.AddFromTemplate(tempfile, targetFileName);
            }

            if (open)
            {
                Window wnd = projectItem.Open(Constants.vsViewKindPrimary);
                wnd.Visible = true;
                wnd.Activate();
            }

            File.Delete(tempfile);
        }

        /// <summary>
        /// Undoes the creation of the item, then deletes the item
        /// </summary>
        public override void Undo()
        {
            if (projectItem != null)
            {
                projectItem.Delete();
            }
        }
    }
}
